package com.mai4j.maiadmin.support.security.aop;

import com.mai4j.maiadmin.support.security.aop.annotation.*;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * 微信公众号请关注: 开源螺丝钉
 * <br>
 * 码云请关注: <a href="https://gitee.com/xiyoufang">https://gitee.com/xiyoufang</a>
 * <br>
 * 哔哩哔哩请关注: <a href="https://space.bilibili.com/438927834">https://space.bilibili.com/438927834</a>
 * 实现一套类似Shiro的注解
 *
 * @author xiyoufang
 */
@Component
public class MaiAuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {

    private static final List<Class<? extends Annotation>> ANNOTATION_CLASSES =
            Arrays.asList(
                    RequiresAuthentication.class,
                    RequiresGuest.class,
                    RequiresPermissions.class,
                    RequiresAccessPermission.class,
                    RequiresModifyPermission.class);

    public MaiAuthorizationAttributeSourceAdvisor() {
        setAdvice(new AopAnnotationsAuthorizingMethodInterceptor());
    }

    public boolean matches(Method method, Class<?> targetClass) {
        if (isAuthorizingAnnotationPresent(method)) {
            return true;
        }
        try {
            Method m = targetClass.getMethod(method.getName(), method.getParameterTypes());
            return isAuthorizingAnnotationPresent(m) || isAuthorizingAnnotationPresent(targetClass);
        } catch (NoSuchMethodException ignored) {
            //default return value is false.  If we can't find the method, then obviously
            //there is no annotation, so just use the default return value.
        }
        return false;
    }

    private boolean isAuthorizingAnnotationPresent(Class<?> targetClazz) {
        for (Class<? extends Annotation> annClass : ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(targetClazz, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }

    private boolean isAuthorizingAnnotationPresent(Method method) {
        for (Class<? extends Annotation> annClass : ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }
}